package com.superbit.service.user.impl;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.transaction.Transactional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.superbit.core.constant.UserStatusConstant;
import com.superbit.core.entry.UserActivityInfo;
import com.superbit.core.entry.UserBaseInfo;
import com.superbit.core.entry.UserSafeInfo;
import com.superbit.core.exception.BusinessException;
import com.superbit.core.service.RegisterService;
import com.superbit.core.service.UserSafeService;
import com.superbit.service.user.daodefine.AppConfigDao;
import com.superbit.service.user.daodefine.UserActivityInfoDao;
import com.superbit.service.user.daodefine.UserBaseInfoDao;
import com.superbit.service.user.daodefine.UserRedisDao;
import com.superbit.service.user.daodefine.UserSafeInfoDao;
import com.superbit.service.util.CommonUtils;
import com.superbit.service.util.GoogleAuthUtils;
import com.superbit.service.util.StringTools;
import com.superbit.utils.constantutil.CollectionUtils;
import com.superbit.utils.constantutil.FixedTime;
import com.superbit.utils.dbutil.RedisKeyUtils;
import com.superbit.utils.mailutil.EmailFailException;
import com.superbit.utils.mobileutil.MobileMessService;

/** @author  WangZhenwei 
  * @date 创建时间：2018年1月15日 上午10:46:03  
  * @descrip 用户安全设置的实现类
  */
@Transactional
@Service
public class UserSafeServiceImpl implements UserSafeService{

	private static Logger log = LoggerFactory.getLogger(UserSafeServiceImpl.class);
	
	@Autowired
	private UserRedisDao userRedisDao;
	
	@Autowired
	private UserBaseInfoDao userBaseInfoDao;
	
	@Autowired
	private UserSafeInfoDao userSafeInfoDao;
		
	@Autowired
	private RegisterService registerService; 
	
	@Autowired
	private MobileMessService mobileMessService;
	
	private int phoneSendLimit;
	
	@Autowired
	private AppConfigDao appConfigDao;
	
    private int phoneMessageVerifyLimit;
	
	private int phoneMessageSendLimit;
	
	private int emailMessageVerifyLimit;
	
	private int emailMessageSendLimit;
	
//	@Value("${ctx}")
	private String ctx;
	
	/*@PostConstruct
	private void init(){
		logger = LoggerFactory.getLogger(this.getClass());
		phoneMessageSendLimit = appConfigDao.getAppConfigIntValue("phoneMessageSendLimit", 5);
		phoneMessageVerifyLimit = appConfigDao.getAppConfigIntValue("phoneMessageVerifyLimit", 5);
		emailMessageSendLimit = appConfigDao.getAppConfigIntValue("emailMessageSendLimit", 5);
		emailMessageVerifyLimit = appConfigDao.getAppConfigIntValue("emailMessageVerifyLimit", 5);
	}*/
	
	@PostConstruct
	private void init(){
		phoneSendLimit = appConfigDao.getAppConfigIntValue("phoneSendLimit", 5);
		phoneMessageSendLimit = appConfigDao.getAppConfigIntValue("phoneMessageSendLimit", 5);
	}
	
	/**
	 * 根据用户旧登录密码更改新登录密码
	 * @throws BusinessException 
	 * 
	 */
	@SuppressWarnings("unused")
	@Override
	public void changePasswordByOldPassword(int userId, String oldPassword, String newPassword) throws BusinessException {
		// 验证旧登录密码是否正确
		UserBaseInfo userBaseInfo = userBaseInfoDao.getUserBaseInfoById(userId);
		if(null == userBaseInfo){
			throw new BusinessException("US620", " The user info doesn't exist!", null);
		}
				
		int length = newPassword.length();
		// 密码安全等级
		byte passwordLevel = 0;
		if(length <= 12){
			passwordLevel = 1;
		}else if(length <= 16){
			passwordLevel = 2;
		}else{
			passwordLevel = 3;
		}
		// 对密码进行MD5加密
		newPassword = CommonUtils.EncoderByMd5(newPassword);
		oldPassword = CommonUtils.EncoderByMd5(oldPassword);
		if(!oldPassword.equals(userBaseInfo.getPassword())){
			// 如旧密码不正确，不允许修改账户
			throw new BusinessException("US621", "Wrong old password!", null);
		}
		UserBaseInfo userInfo = new UserBaseInfo();
		userInfo.setUserId(userId);
		userInfo.setPassword(newPassword);
		// 自修改登录密码起，24小时内禁止提币
		userBaseInfoDao.updateLoginPwdInfoByUserId(userInfo);
		// 【冻结提币操作的事件】
		UserSafeInfo safeInfo = new UserSafeInfo();
		safeInfo.setUserId(userId);
		safeInfo.setFreezeStatus(UserStatusConstant.USER_STATUS_RESETPWD);  // 2表示修改登录密码禁止提现的状态
		safeInfo.setFreezeDeadline(FixedTime.getTomorrow());
		userSafeInfoDao.freezeUserForResetPwd(safeInfo);
	}

	/**
	 * 查询昵称是否存在
	 */
	@Override
	public boolean checkNickname(String nickname) {
		int nicknameCount = userBaseInfoDao.countUserInfoByNickname(nickname);
		if(nicknameCount == 0){
			return true;
		}
		return false;
	}

	/**
	 * 保存昵称和资金密码
	 */
	@Override
	public void setNicknameAndFundPassword(Integer userId, String nickname, String fundPassword) {
		log.info("设置昵称和资金密码：用户ID，昵称，资金密码", Arrays.toString(new Object[]{userId,nickname,fundPassword}));
		
		UserBaseInfo userBaseInfo = new UserBaseInfo();
		UserSafeInfo userSafeInfo = new UserSafeInfo();
		userBaseInfo.setUserId(userId);
		userBaseInfo.setNickname(nickname);
		userSafeInfo.setUserId(userId);
		userSafeInfo.setFundPassword(CommonUtils.EncoderByMd5(fundPassword));
		// 更新昵称和资金密码到数据库
		userBaseInfoDao.updateUserBaseInfoByUserId(userBaseInfo);
		
		userSafeInfoDao.updateUserSafeInfo(userSafeInfo);
	}

	/**
	 * 申请手机绑定
	 * @throws BusinessException 
	 */
	@Override
	public boolean applyForPhoneBind(Integer userId, String phone, String areaCode) throws BusinessException {
		UserBaseInfo userBaseInfo = userBaseInfoDao.getUserBaseInfoById(userId);
		if(!StringTools.isBlank(userBaseInfo.getPhone())){
			throw new BusinessException("US623", " already apply bind", null);
		}
		int countPhone = userBaseInfoDao.countUserByPhone(phone);
		if(countPhone>=1){
			throw new BusinessException("US652", "The phone has been used!", null);
		}
		Map<String, Object> codeMap = new HashMap<String, Object>();
		String code = CommonUtils.randCode("", UserStatusConstant.CHECK_CODE_LENGTH);
		Map<String, String> map = userRedisDao.getPhoneRegisterTempInfo(phone);
		if(null == map ||map.isEmpty() || Integer.parseInt(map.get("phoneSendCount")+"")<phoneSendLimit){
			Map<String, String> hash = new HashMap<String, String>();
			codeMap.put("code", code);
			mobileMessService.sendMessage(phone, "1", true, codeMap); //发送短信的服务
			
			int count = 0;
			if(null != map && !map.isEmpty()){
				count = Integer.parseInt(map.get("phoneSendCount"));
			}
			hash.put("areaCode", areaCode);
			hash.put("phoneSendCount", count + 1 + "");
			hash.put("phoneMessageVerifyCount", 0 + "");
			hash.put("phoneMessageSendTime", System.currentTimeMillis()+"");
			hash.put("phone", phone);
			hash.put("captcha", codeMap.get("code")+"");
			
			userRedisDao.savePhoneRegisterTempInfo(hash);
			return true;
		}
		throw new BusinessException("US602", "Phone message delivery exceeds " 
				+ phoneSendLimit + " limit!", null);
	}

	/**
	 * 绑定手机,更新手机号信息及安全级别到数据库中
	 */
	@SuppressWarnings("unused")
	@Override
	public void bindPhone(Integer userId, String captcha, String phone) throws BusinessException {
		Map<String, String> tempInfo = registerService.verifyCodeByPhone(phone, captcha);
		
		String areaCode = tempInfo.get("areaCode");
		String phoneTemp = tempInfo.get("phone");
		
		// 1更新用户基本信息
		UserBaseInfo baseInfo = new UserBaseInfo();
		baseInfo.setUserId(userId);
		baseInfo.setAreaCode(areaCode);
		baseInfo.setPhone(phoneTemp);
		
		// 2更新用户安全信息
		UserSafeInfo safeInfo = new UserSafeInfo();
		safeInfo.setUserId(userId);
		safeInfo.setBindPhone(UserStatusConstant.BIND_PHONE_YES);
		safeInfo.setSecurityLevel(UserStatusConstant.SECURITY_LEVEL_PHONE);
		
		userBaseInfoDao.bindPhoneInfoById(baseInfo);
		userSafeInfoDao.updatePhoneInfoById(safeInfo);
		
		/*// 对密码进行MD5加密
		password = CommonUtils.EncoderByMd5(password);
		// 创建用户基础信息对象		
        Date time = FixedTime.getCurrentTime();		
		UserBaseInfo userBaseInfo = new UserBaseInfo("", "", password, areaCode, phoneTemp, time, (byte)UserStatusConstant.USER_ACCOUNT_PHONE);
		Integer userId = userBaseInfoDao.saveUserBaseInfo(userBaseInfo);
		// 创建用户安全信息对象
		int loginAuthentication = appConfigDao.getAppConfigIntValue("loginAuthentication", 1);
		Date current = FixedTime.getCurrentTime();
		UserSafeInfo userSafeInfo = new UserSafeInfo(userId, "", "",(byte)UserStatusConstant.BIND_PHONE_YES, (byte)UserStatusConstant.SECURITY_LEVEL_PHONE, (byte)loginAuthentication,(byte)UserStatusConstant.AUTHEN_STATUS_INIT ,(byte)UserStatusConstant.USER_STATUS_ACTIVE, null, (byte)UserStatusConstant.LOCK_STATUS_NONE, 0, current, passwordLevel);
		userSafeInfoDao.saveUserSafeInfo(userSafeInfo);
		// 创建用户活动信息对象
		Date current1 = FixedTime.getCurrentTime();
		UserActivityInfo userActivityInfo = new UserActivityInfo(userId, (byte)1, 0, current1);
		userActivityInfoDao.saveUserActivityInfo(userActivityInfo);
		
		// 添加完成后将用户Id返回给前台用户
		return CollectionUtils.buildMap("userId", userId);*/
		/*long captchaTime = RedisKeyUtils.getCaptchaValidTime();
		Map<String, String> tempInfo = userRedisDao.getPhoneRegisterTempInfo(phone);
		if(null == tempInfo || tempInfo.isEmpty()){  // 不存在验证码，绑定失败
			throw new BusinessException("US653","No phone needs to be activated!", null);
		}
		String mobile = tempInfo.get("phone") + "";
		String captchaTemp = tempInfo.get("captcha");// redis中存的验证码
		long phoneSendTime = Long.parseLong(tempInfo.get("phoneSendTime") + "");
		int phoneVerifyCount = Integer.parseInt(tempInfo.get("phoneVerifyCount") + "");
		if(phoneVerifyCount >= phoneSendLimit){
			throw new BusinessException("US603", "Captcha verify exceeds "+ phoneSendLimit +" limit!", null);
		}
		if(!captcha.equals(captchaTemp)){//验证码不匹配，验证失败
			userRedisDao.incVerifyCount(phone);
			throw new BusinessException("US605", "Captcha is error!", null);
		}
		long currentTime = System.currentTimeMillis();
		if(currentTime - phoneSendTime > captchaTime*1000){
			throw new BusinessException("US604", "Captcha is invalid!", null);
		}
		
		// 更新手机信息到数据库中UserBaseInfo UserSafeInfo
		userSafeInfoDao.updateUserSafeInfo(userSafeInfo);
		userBaseInfoDao.updateUserBaseInfoByUserId(userBaseInfo);
		
		// 删除手机绑定的临时信息
		userRedisDao.removePhoneRegisterTempInfo(phone);*/
	}

	/**
	 * 根据用户Id获取用户安全信息
	 */
	@Override
	public UserSafeInfo getUserSafeInfo(Integer userId) {
		return userSafeInfoDao.getUserSafeInfoById(userId);
	}

	/**
	 * 根据用户Id向指定手机发送验证码信息
	 * 
	 */
	@Override
	public void getPhoneCodeByUserId(Integer userId) throws BusinessException {
		UserBaseInfo userBaseInfo = userBaseInfoDao.getUserBaseInfoById(userId);
		if(null == userBaseInfo){
			throw new BusinessException("US620", "The user info doesn't exist!", null);
		}
		
		String areaCode = userBaseInfo.getAreaCode();
		String phone = userBaseInfo.getPhone();
		
		//registerService.phoneRegister(areaCode, phone);
		this.phoneVerify(areaCode, phone);
		/*// 1.根据手机号统计使用该手机号注册的人数
				int count = userBaseInfoDao.countUserByPhone(phone);
				if(count == 0){
					throw new BusinessException("US652","The phone has been used!",null);
				}
				// 2.验证用户输入的验证码（错误给提示、超过限制次数）
				Map<String,String> tempInfo = userRedisDao.getPhoneRegisterTempInfo(phone);
				  // 手机发送次数限制为5次
				if(null==tempInfo || tempInfo.isEmpty()||Integer.parseInt(tempInfo.get("phoneMessageSendCount")+"") < phoneMessageSendLimit){   // 待优化
					int phoneMessageSendCount = 0;
					// 手机注册的临时信息存在
					if(null != tempInfo && !tempInfo.isEmpty()){
						phoneMessageSendCount  = Integer.parseInt(tempInfo.get("phoneMessageSendCount")+"");
					}else{
						tempInfo  = new HashMap<String,String>();
					}
					
					// 生成六位随机数的验证码
					String captcha = CommonUtils.randCode("", UserStatusConstant.CHECK_CODE_LENGTH);
					// 发送短信验证码
					//this.sendMessage(areaCode, phone, 1, 1, "activeMobile", CollectionUtils.buildMap("code", captcha), true);
					mobileMessService.sendMessage(phone, "phoneRegister", true, CollectionUtils.buildMap("code", captcha));
					//this.sendMessage(areaCode, phone, 1, 1, "");
					
					tempInfo.put("areaCode", areaCode);
					tempInfo.put("phone", phone);
					tempInfo.put("captcha", captcha);
					tempInfo.put("phoneMessageSendCount", phoneMessageSendCount + 1 + "");
					tempInfo.put("phoneMessageVerifyCount", "0");
					tempInfo.put("phoneMessageSendTime", System.currentTimeMillis()+"");
					// 保存手机注册的临时信息到redis数据库中
					userRedisDao.savePhoneRegisterTempInfo(tempInfo);
				}else {
					log.error("US602", "Phone message delivery exceeds Limit");
					throw new BusinessException("US602", "Phone message delivery exceeds " 
							+ phoneMessageSendLimit + " limit!", null);
				}*/
	}

	/**
	 * 根据用户Id验证手机验证码
	 * @param userId
	 */
	@Override
	public void verifyPhoneCodeByUserId(Integer userId, String phoneCaptcha) throws BusinessException {
		UserBaseInfo userBaseInfo = userBaseInfoDao.getUserBaseInfoById(userId);
		if(null == userBaseInfo){
			throw new BusinessException("US753", "The user is not exist!", null);
		}
		String phone = userBaseInfo.getPhone();
		registerService.verifyCodeByPhone(phone, phoneCaptcha);		
	}

	/**
	 * 根据用户Id验证谷歌验证码
	 * @param userId
	 */
	@Override
	public void verifyGoogleCodeByUserId(Integer userId, String googleCaptcha) throws BusinessException {
		UserBaseInfo userBaseInfo = userBaseInfoDao.getUserBaseInfoById(userId);
		UserSafeInfo userSafeInfo = userSafeInfoDao.getUserSafeInfoById(userId);
		if(null == userBaseInfo){
			throw new BusinessException("US753", "The user is not exist!", null);
		}
		String googlePrivateKey = userSafeInfo.getGooglePrivateKey();
		// 调用谷歌认证接口进行验证
		boolean isAuth = GoogleAuthUtils.authcode(googleCaptcha, googlePrivateKey);
		if(!isAuth){
			throw new BusinessException("US606", "GoogleCaptcha is error!", null);
		}
		//registerService.verifyCodeByPhone(phone, captcha)
	}

	/**
	 * 根据用户Id验证邮件验证码
	 * @param userId
	 * @throws BusinessException 
	 */
	@Override
	public void verifyEmailCodeByUserId(Integer userId,String email,String emailCaptcha) throws BusinessException {
		UserBaseInfo userBaseInfo = userBaseInfoDao.getUserBaseInfoById(userId);
		if(null == userBaseInfo){
			throw new BusinessException("US753", "The user is not exist!", null);
		}
		registerService.verifyCodeByEmail(email, emailCaptcha);
	}

	/**
	 * 根据用户ID绑定邮箱信息
	 */
	@Override
	public void bindEmailByUserId(Integer userId, String email) {
		UserBaseInfo userBaseInfo = new UserBaseInfo();
		userBaseInfo.setUserId(userId);
		userBaseInfo.setEmail(email);
		// 绑定邮箱之更新邮箱信息
		userBaseInfoDao.updateEmailInfoByUserId(userBaseInfo);
	}

	/**
	 * 生成谷歌APP验证码并存到redis中
	 * 
	 */
	
	@Override
	public Map<String, Object> getGoogleAuth(Integer userId) throws BusinessException {
		UserSafeInfo userSafeInfo = userSafeInfoDao.getUserSafeInfoById(userId);
		UserBaseInfo userBaseInfo = userBaseInfoDao.getUserBaseInfoById(userId);
		if(!StringTools.isBlank(userSafeInfo.getGooglePrivateKey())){
			throw new BusinessException("US801", "The user has bind the googlePrivateKey!", null);
		}
		String secret = GoogleAuthUtils.genSecret();
		// 判断用户是邮箱账户还是手机账户
		String account = "";
		if("1".equals(userBaseInfo.getAccountType())){
			account = userBaseInfo.getEmail();
		}else{
			account = userBaseInfo.getPhone();
		}
		String QRsecret = GoogleAuthUtils.getQRBarcodeURL(account, secret);
		
		userRedisDao.setGoogleSecret(userId, secret); // 谷歌私钥存入redis
		HashMap<String, Object> returnData = new HashMap<>();
		returnData.put("secret", secret);
		returnData.put("QRsecret", QRsecret);
		return returnData;
	}

	/**
	 * 根据用户ID保存用户谷歌私钥的方法，设置用户安全级别为2==【高】
	 * @param userId
	 * @return
	 * @throws BusinessException 
	 */
	@Override
	public void bindGoogleAuth(Integer userId) throws BusinessException {
		UserSafeInfo userSafeInfo = userSafeInfoDao.getUserSafeInfoById(userId);
		if(!StringTools.isBlank(userSafeInfo.getGooglePrivateKey())){
			throw new BusinessException("US801", "The user has bind the googlePrivateKey!", null);
		}
		String secret = userRedisDao.getGoogleSecret(userId);
		if(StringTools.isBlank(secret)){
			throw new BusinessException("US803", "TempGooglePrivateKey is not exist!", null);
		}
		userSafeInfo.setGooglePrivateKey(secret);
		userSafeInfo.setSecurityLevel((byte)2);  // 2==用户安全级别高
		userSafeInfoDao.updateUserSafeInfo(userSafeInfo);
		userRedisDao.dropGoogleSecret(userId);
	}

	/**
	 * 根据用户ID更新用户资金密码的业务方法
	 * @param userId
	 * @param newFundPassword
	 */
	@Override
	public void changeFundPassword(Integer userId, String newFundPassword) {
		UserSafeInfo userSafeInfo = userSafeInfoDao.getUserSafeInfoById(userId);
		String fundPassword = CommonUtils.EncoderByMd5(newFundPassword);
		userSafeInfo.setFundPassword(fundPassword);
		userSafeInfoDao.updateUserSafeInfo(userSafeInfo);
	}

	/**
	 * 获取手机验证码
	 * 
	 */	
	public void phoneVerify(String areaCode, String phone) throws BusinessException {
		// 1.根据手机号统计使用该手机号注册的人数
		int count = userBaseInfoDao.countUserByPhone(phone);
		if(count == 0){
			throw new BusinessException("US654","No binding phone!",null);
		}
		// 2.验证用户输入的验证码（错误给提示、超过限制次数）
		Map<String,String> tempInfo = userRedisDao.getPhoneRegisterTempInfo(phone);
		  // 手机发送次数限制为5次
		if(null==tempInfo || tempInfo.isEmpty()||Integer.parseInt(tempInfo.get("phoneMessageSendCount")+"") < phoneMessageSendLimit){   // 待优化
			int phoneMessageSendCount = 0;
			// 手机注册的临时信息存在
			if(null != tempInfo && !tempInfo.isEmpty()){
				phoneMessageSendCount  = Integer.parseInt(tempInfo.get("phoneMessageSendCount")+"");
			}else{
				tempInfo  = new HashMap<String,String>();
			}
			
			// 生成六位随机数的验证码
			String captcha = CommonUtils.randCode("", UserStatusConstant.CHECK_CODE_LENGTH);
			// 发送短信验证码
			//this.sendMessage(areaCode, phone, 1, 1, "activeMobile", CollectionUtils.buildMap("code", captcha), true);
			mobileMessService.sendMessage(phone, "phoneRegister", true, CollectionUtils.buildMap("code", captcha));
			//this.sendMessage(areaCode, phone, 1, 1, "");
			
			tempInfo.put("areaCode", areaCode);
			tempInfo.put("phone", phone);
			tempInfo.put("captcha", captcha);
			tempInfo.put("phoneMessageSendCount", phoneMessageSendCount + 1 + "");
			tempInfo.put("phoneMessageVerifyCount", "0");
			tempInfo.put("phoneMessageSendTime", System.currentTimeMillis()+"");
			// 保存手机注册的临时信息到redis数据库中
			userRedisDao.savePhoneRegisterTempInfo(tempInfo);
		}else {
			log.error("US602", "Phone message delivery exceeds Limit");
			throw new BusinessException("US602", "Phone message delivery exceeds " 
					+ phoneMessageSendLimit + " limit!", null);
		}
				
	}
	
	
	/**
	 * 获取邮箱验证码
	 * @throws BusinessException 
	 * @throws EmailFailException 
	 */
	
	/*public void emailVerify(String email) throws BusinessException, EmailFailException {
		// 1.根据邮箱统计使用该邮箱的人数
		int count = userBaseInfoDao.countUserByEmail(email);
		if(count > 0){
			log.error("US702", "The email has been used!");
			throw new BusinessException("US702","The email has been used!",null);
		}
		// 2.验证用户输入的验证码（错误提示、超限提示）
		Map<String, String> tempInfo = userRedisDao.getEmailRegisterTempInfo(email);
		if(null!=tempInfo || !tempInfo.isEmpty() || Integer.parseInt(tempInfo.get("emailMessageSendCount")+"") < emailMessageSendLimit){
			int emailMessageSendCount = 0;
			// 邮箱注册的临时信息存在
			if(null != tempInfo && !tempInfo.isEmpty()){
				emailMessageSendCount = Integer.parseInt(tempInfo.get("emailMessageSendCount") + "");
			}else{
				tempInfo = new HashMap<String,String>();
			}
			
			// 生成六位随机数的验证码
			String captcha = CommonUtils.randCode("", UserStatusConstant.CHECK_CODE_LENGTH);
			Map<String, Object> accessData = CollectionUtils.buildMap("email",email,"activeCode",captcha,"toEmail",email,"ctx",ctx);
			// 发送邮箱验证码
			//this.sendEmail(email, "active", 1, accessData, true);
			emailSendService.sendMessage(email, "emailRegister", true, accessData);
			tempInfo = CollectionUtils.buildMap("email",email,"captcha",captcha,"emailMessageSendCount",emailMessageSendCount+1+"","emailMessageVerifyCount","0","emailMessageSendTime",System.currentTimeMillis()+"");
			// 在Redis中保存邮件注册的临时信息
			userRedisDao.saveEmailRegisterTempInfo(tempInfo);
		}else{
			log.error("US619", "Email message delivery exceeds Limit");
			throw new BusinessException("US619", "Email message delivery exceeds " 
					+ emailMessageSendLimit + " limit!", null);
		}
	}*/
	
}
